package nets

import (
	"net"

	"gitee.com/xuender/oils/logs"
	"gitee.com/xuender/pp"
)

const (
	maxSize = 10 * 1024
	ip255   = 255
)

// UDPService UDP服务.
type UDPService struct {
	Conn     UDPConn
	buffSize int
}

// NewUDPService 新建UDP服务.
func NewUDPService(config *pp.Config) *UDPService {
	s := &UDPService{buffSize: config.BuffSize}
	if s.buffSize == 0 {
		s.buffSize = maxSize
	}

	var err error

	s.Conn, err = net.ListenUDP("udp4", &net.UDPAddr{
		IP:   net.IPv4(0, 0, 0, 0),
		Port: config.UDPPort,
	})

	if err != nil {
		panic(err)
	}

	return s
}

// Close 关闭.
func (s *UDPService) Close() error {
	if s.Conn == nil {
		return ErrNoConn
	}
	// nolint: wrapcheck
	return s.Conn.Close()
}

// Call 发送消息.
func (s *UDPService) Call(port int, data []byte, ip ...byte) (int, error) {
	logs.Debug("广播:", port)
	if len(ip) < 4 {
		ip = append(ip, []byte{ip255, ip255, ip255, ip255}[0:4-len(ip)]...)
	}
	// nolint: wrapcheck
	return s.Conn.WriteToUDP(data, &net.UDPAddr{
		IP:   net.IPv4(ip[0], ip[1], ip[2], ip[3]),
		Port: port,
	})
}

// Listen 监听.
func (s *UDPService) Listen(call func(*net.UDPAddr, []byte)) (err error) {
	for {
		data := make([]byte, s.buffSize)

		read, remoteAddr, err := s.Conn.ReadFromUDP(data)
		if err != nil {
			// nolint: wrapcheck
			return err
		}

		call(remoteAddr, data[:read])
	}
}
